<?php

function ddi_validator_validate(){
	drupal_add_css(drupal_get_path('module', 'ddi_validator').'/ddi_validator.css');
	return drupal_get_form('ddi_validator_form');
}

function ddi_validator_validate_test(){
	drupal_add_css(drupal_get_path('module', 'ddi_validator').'/ddi_validator.css');
	$text = file_get_contents(drupal_get_path('module', 'ddi_validator').'/SSI-ddi3.xml');
	
	$result = validate_ddi($text);
	
	$output = '';
	switch($result['status']){
		case 'invalid':
			drupal_set_message('Document is invalid<br /><pre>'.print_r($result['message'],true).'</pre>', 'warning');
		break;
		
		case 'valid':
			drupal_set_message('VALID!', 'status');
			$output .= '<img src="/'.drupal_get_path('module', 'ddi_validator').'/img/ddi3_1.png" />';
		break;
	}

	return $output;
}

/** Prettifies an XML string into a human-readable and indented work of art 
 *  @param string $xml The XML as a string 
 *  @param boolean $html_output True if the output should be escaped (for use in HTML) 
 */  
function xmlpp($xml, $html_output=false) {  
    $xml_obj = new SimpleXMLElement($xml);  
    $level = 4;  
    $indent = 0; // current indentation level  
    $pretty = array();  
      
    // get an array containing each XML element  
    $xml = explode("\n", preg_replace('/>\s*</', ">\n<", $xml_obj->asXML()));  
  
    // shift off opening XML tag if present  
    if (count($xml) && preg_match('/^<\?\s*xml/', $xml[0])) {  
      $pretty[] = array_shift($xml);  
    }  
  
    foreach ($xml as $el) {  
      if (preg_match('/^<([\w])+[^>\/]*>$/U', $el)) {  
          // opening tag, increase indent  
          $pretty[] = str_repeat(' ', $indent) . $el;  
          $indent += $level;  
      } else {  
        if (preg_match('/^<\/.+>$/', $el)) {              
          $indent -= $level;  // closing tag, decrease indent  
        }  
        if ($indent < 0) {  
          $indent += $level;  
        }  
        $pretty[] = str_repeat(' ', $indent) . $el;  
      }  
    }     
    $xml = implode("\n", $pretty);     
    return ($html_output) ? htmlentities($xml) : $xml;  
}  


function ddi_validator_form_submit($form, &$form_state) {	
	if (isset($_FILES['files']) && is_uploaded_file($_FILES['files']['tmp_name']['file'])) {
		// attempt to save the uploaded file
		$file = file_save_upload('file');

		// set error if file was not uploaded
		if (!$file) {
		  form_set_error($fieldName, 'Error uploading file.');
		  return;
		}
		   
		// set files to form_state, to process when form is submitted
		$form_state['values']['file'] = $file;
	}

	if ($form_state['values']['file'] != '') {
		$text = file_get_contents($form_state['values']['file']->filepath);
		$encoding = 'UTF-8';
		//dsm(mb_detect_encoding($text, "auto"));
		if((chr(0xFF).chr(0xFE)) == substr($text, 0, 2)){
			$encoding = 'UTF-16';
		}
		
		$result = ddi_validator_validate_file(array(
												'file'=>$form_state['values']['file']->filepath,
												'encoding' => $encoding
											  ));
	}else if ($form_state['values']['url'] != '') {
		$text   = ddi_validator_get_text_from_url($form_state['values']['url']);
		$result = ddi_validator_validate_file(array('document'=>$text));
	}else if ($form_state['values']['document'] != '') {
		$text   = $form_state['values']['document'];
		$result = ddi_validator_validate_file(array('document'=>$text));
	}
	
	$lines =explode("\n",$text);
	
	$result = ddi_validator_parse_response($result);
	
	switch($result['status']){
		case 'invalid':
			if(is_array($result['message'])){
				$msg = '<table><tr><td>line</td><td>column</td><td>message</td></tr>';
				foreach($result['message'] as $m){
					$msg .= '<tr><td>'.$m['line'].'</td><td>'.$m['column'].'</td><td><strong>'.$m['msg'].'</strong><br />'.htmlspecialchars($lines[$m['line']]).'</td></tr>';
				}
				$msg .= '</table>';
			}
		
			drupal_set_message(t('Document is invalid').':<br/> '.$msg, 'warning');
		break;
		
		case 'valid':
			$output = '<img src="/'.drupal_get_path('module', 'ddi_validator').'/img/ddi3_1.png" />';
			drupal_set_message($output.' '.t('The document is valid'), 'status');
		break;
	}
}

function ddi_validator_form($form_state){
	$form = array();
	
	$form['#attributes'] = array('enctype' => "multipart/form-data");
	$form['#redirect'] = FALSE;
	
	$form['url'] = array(
	  '#type' => 'textfield',
	  '#title' => t('URL to DDI'),
	  '#size' => 60,
	  '#maxlength' => 264,
	  '#description' => t('the full url to a DDI document'),
	);
	$form['file'] = array(
	  '#type' => 'file',
	  '#title' => t('DDI-file'),
	  '#description' => t('DDI file to validate'),
	);	
	$form['document'] = array(
	  '#type' => 'textarea',
	  '#title' => t('DDI xml'),
	  '#size' => 60,
	  '#attributes' => array('style' => 'margin-bottom: 0px;'),
	  '#description' => t('DDI 2.x or 3.x'),
	);
	
	$form['version'] = array(
	  '#type' => 'select',
	  '#title' => t('DDI Version'),
	  '#options' => array(
		'autodetect' 	=> t('Autodetect'),
		'ddi3_1' 		=> 'DDI 3.1',
		'ddi2_1' 		=> 'DDI 2.1',
	  ),
	  '#description' => t('The validator tries to autodetect however you can specify the version'),
	);	
	
	$form['submit'] = array(
	  '#type' => 'submit',
	  '#value' => t('Validate'),
	);
	
	return $form;
}

function ddi_validator_get_text_from_url($url){
	$result = drupal_http_request($url);
	return $result->data;
}

function validate_ddi($text, $version = ''){	
	$validate_url = variable_get('ddi_validator_url', "http://bull.ssd.gu.se:8080/exist/rest/db/ddi3/ws/validate.xql");
	
	// Set some parameters for sending request.
	$request_url = $validate_url;
	$request_headers = array('Content-Type' => 'application/x-www-form-urlencoded');
	$request_method = 'POST';
	$request_retry = 3;
	
	$vars = array('document' => $text, 'version' => $version);
	$data = http_build_query($vars, '', '&');
	 
	// Send the request.
	ini_set('default_socket_timeout','1200');
	$result = drupal_http_request($request_url, $request_headers, $request_method, $data, $request_retry);
	
	return $result->data;
}

function ddi_validator_parse_response($reponse){
	$output = array();
	
	//parse xml
	$xml = simplexml_load_string($reponse);
		
	$output['status'] 	= (string)$xml->status;
	if(empty($output['status']))
		$output['status'] = 'invalid';
	
	$output['duration'] = (string)$xml->duration;
	
	foreach($xml->xpath('//message') as $m){
		$msg['column'] 	= (string)$m->attributes()->column;
		$msg['line'] 	= (string)$m->attributes()->line;
		$msg['level'] 	= (string)$m->attributes()->level;
		$msg['msg'] 	= (string)$m;
		$output['message'][] = $msg;
	}
	
	return $output;
}

/*
/ File validation for DDI
*/
function ddi_validator_validate_file($params){
    $request_url = variable_get('ddi_validator_url', "http://bull.ssd.gu.se:8080/exist/rest/db/ddi3/ws/validate.xql");
		
	$boundary = 'A0sFSD';
    $headers = array("Content-Type" => "multipart/form-data; boundary=$boundary");
    $request = drupal_http_request($request_url, $headers, 'POST', ddi_validator_multipart_encode($boundary, $params));
    if ($request->error)
      watchdog("ddi_validator", "Request failed - ". $request->error .' - '. http_build_query($params));
    return $request->data;
}

function ddi_validator_multipart_encode($boundary, $params){
  $output = "";
  foreach ($params as $key => $value){
    $output .= "--$boundary\r\n";
    if ($key == 'file'){
      $output .= ddi_validator_multipart_enc_file($value);
    } else $output .= ddi_validator_multipart_enc_text ($key, $value);
  }
  $output .="--$boundary--";
  return $output;
}

function ddi_validator_multipart_enc_text($name, $value){
  return "Content-Disposition: form-data; name=\"$name\"\r\n\r\n$value\r\n";
}

function ddi_validator_multipart_enc_file($path){
  if (substr($path, 0, 1) == "@") $path = substr($path, 1);
  $filename = basename($path);
  $mimetype = "application/octet-stream";
  $data = "Content-Disposition: form-data; name=\"upload\"; filename=\"$filename\"\r\n";
  $data .= "Content-Transfer-Encoding: binary\r\n";
  $data .= "Content-Type: $mimetype\r\n\r\n";
  $data .= removeBOM(file_get_contents($path)) . "\r\n";
  return $data;
}

function removeBOM($str=""){
        if(substr($str, 0,3) == pack("CCC",0xef,0xbb,0xbf)) {
                $str=substr($str, 3);
        }
        return $str;
}
?>